//! 词法扫描器
//! 
//! 实现将源代码字符串转换为 Token 序列的功能

use crate::error::{AssemblerError, Result};
use super::token::Token;

/// 词法分析器
pub struct Lexer {
    input: Vec<char>,
    position: usize,
    line: usize,
    column: usize,
}

impl Lexer {
    /// 创建新的词法分析器
    pub fn new(input: &str) -> Self {
        Self {
            input: input.chars().collect(),
            position: 0,
            line: 1,
            column: 1,
        }
    }

    /// 获取当前位置信息（用于错误报告）
    pub fn position(&self) -> (usize, usize) {
        (self.line, self.column)
    }

    /// 查看下一个字符（不移动位置）
    fn peek(&self) -> Option<char> {
        self.input.get(self.position).copied()
    }

    /// 查看下 n 个字符（不移动位置）
    fn peek_n(&self, n: usize) -> Option<char> {
        self.input.get(self.position + n).copied()
    }


    /// 消费当前字符并前进
    fn advance(&mut self) -> Option<char> {
        let ch = self.peek()?;
        self.position += 1;
        if ch == '\n' {
            self.line += 1;
            self.column = 1;
        } else {
            self.column += 1;
        }
        Some(ch)
    }

    /// 跳过空白字符
    fn skip_whitespace(&mut self) {
        while let Some(ch) = self.peek() {
            if ch.is_whitespace() && ch != '\n' {
                self.advance();
            } else {
                break;
            }
        }
    }

    /// 读取标识符或关键字
    /// 
    /// 只支持中文标识符，允许包含数字（但标识符不能以数字开头）
    fn read_identifier(&mut self) -> String {
        let mut result = String::new();
        while let Some(ch) = self.peek() {
            // 只支持中文字符和数字
            // 中文字符：is_alphabetic() 对中文字符返回 true
            // 数字：允许在标识符中间使用数字，但标识符不能以数字开头（由调用者保证）
            if ch.is_alphabetic() || (ch.is_ascii_digit() && !result.is_empty()) {
                result.push(self.advance().unwrap());
            } else {
                break;
            }
        }
        result
    }

    /// 读取数字
    fn read_number(&mut self) -> Result<i64> {
        let mut result = String::new();
        let mut base = 10;

        // 检查前缀（0x 十六进制，0b 二进制）
        if let Some('0') = self.peek() {
            result.push(self.advance().unwrap());
            if let Some('x') | Some('X') = self.peek() {
                self.advance();
                base = 16;
            } else if let Some('b') | Some('B') = self.peek() {
                self.advance();
                base = 2;
            } else {
                // 可能是八进制，这里简化为十进制
                base = 10;
            }
        }

        // 读取数字部分
        while let Some(ch) = self.peek() {
            if ch.is_digit(base) {
                result.push(self.advance().unwrap());
            } else {
                break;
            }
        }

        // 解析数字
        if base == 10 {
            result.parse::<i64>()
                .map_err(|_| AssemblerError::LexerError {
                    message: format!("无效的数字: {}", result),
                    line: self.line,
                    column: self.column,
                })
        } else {
            // 移除前缀后解析
            let num_str = if result.starts_with("0x") || result.starts_with("0X") {
                &result[2..]
            } else if result.starts_with("0b") || result.starts_with("0B") {
                &result[2..]
            } else {
                &result[1..]
            };
            i64::from_str_radix(num_str, base)
                .map_err(|_| AssemblerError::LexerError {
                    message: format!("无效的数字: {}", result),
                    line: self.line,
                    column: self.column,
                })
        }
    }

    /// 读取下一个 Token
    pub fn next_token(&mut self) -> Result<Token> {
        self.skip_whitespace();

        let ch = match self.peek() {
            Some(ch) => ch,
            None => return Ok(Token::Eof),
        };

        match ch {
            '\n' => {
                self.advance();
                Ok(Token::Newline)
            }
            '“' => {
                // 中文左双引号（“）
                self.read_string()
            }
            '，' => {
                // 中文逗号
                self.advance();
                Ok(Token::Comma)
            }
            '【' => {
                // 中文左方括号
                self.advance();
                Ok(Token::LeftBracket)
            }
            '】' => {
                // 中文右方括号
                self.advance();
                Ok(Token::RightBracket)
            }
            '+' => {
                // 加号运算符
                self.advance();
                Ok(Token::Plus)
            }
            '-' => {
                // 检查是否是注释：如果下一个字符也是 '-'，则作为注释
                // 注释使用 '--'
                if let Some('-') = self.peek_n(1) {
                    // 注释：跳过两个 '-' 和到行尾的所有内容
                    self.advance(); // 消费第一个 '-'
                    self.advance(); // 消费第二个 '-'
                    while let Some(ch) = self.peek() {
                        if ch == '\n' {
                            break;
                        }
                        self.advance();
                    }
                    self.next_token()
                } else {
                    // 减号运算符
                    self.advance();
                    Ok(Token::Minus)
                }
            }
            '*' => {
                // 乘号运算符
                self.advance();
                Ok(Token::Asterisk)
            }
            '：' => {
                // 中文冒号
                self.advance();
                Ok(Token::Colon)
            }
            _ if ch.is_ascii_digit() => {
                let num = self.read_number()?;
                Ok(Token::Number(num))
            }
            _ if ch.is_alphabetic() => {
                // 只支持中文标识符（is_alphabetic() 对中文字符返回 true）
                let ident = self.read_identifier();
                Ok(Token::Identifier(ident))
            }
            _ => {
                Err(AssemblerError::LexerError {
                    message: format!("无法识别的字符: {}", ch),
                    line: self.line,
                    column: self.column,
                })
            }
        }
    }

    /// 读取字符串字面量（新增）
    /// 
    /// 只支持中文双引号（"和"）
    /// 中文引号字符串不支持转义字符，所有字符按字面意思处理
    fn read_string(&mut self) -> Result<Token> {
        let start_line = self.line;
        let start_column = self.column;
        
        // 消费中文左引号（"）
        self.advance();
        
        let mut value = String::new();
        
        // 读取字符串内容，直到遇到中文右引号（"）
        while let Some(ch) = self.peek() {
            // 检查是否是中文右引号（"）
            if ch == '”' {
                self.advance(); // 跳过结束引号
                return Ok(Token::StringLiteral(value));
            }
            
            // 检查是否遇到换行符（字符串不能跨行）
            if ch == '\n' {
                return Err(AssemblerError::LexerError {
                    message: "字符串字面量不能跨行".to_string(),
                    line: self.line,
                    column: self.column,
                });
            }
            
            // 检查是否遇到文件结束
            if ch == '\0' {
                return Err(AssemblerError::LexerError {
                    message: "字符串字面量未闭合，期望中文右引号".to_string(),
                    line: start_line,
                    column: start_column,
                });
            }
            
            // 普通字符，直接添加到字符串
            value.push(ch);
            self.advance();
        }
        
        // 如果到达文件末尾仍未找到结束引号
        Err(AssemblerError::LexerError {
            message: "字符串字面量未闭合，期望中文右引号".to_string(),
            line: start_line,
            column: start_column,
        })
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_basic_tokens() {
        let mut lexer = Lexer::new("加 累加器，123");
        assert_eq!(lexer.next_token().unwrap(), Token::Identifier("加".to_string()));
        assert_eq!(lexer.next_token().unwrap(), Token::Identifier("累加器".to_string()));
        assert_eq!(lexer.next_token().unwrap(), Token::Comma);
        assert_eq!(lexer.next_token().unwrap(), Token::Number(123));
    }

    #[test]
    fn test_chinese_identifiers() {
        let mut lexer = Lexer::new("移动 累加器 基址 计数");
        assert_eq!(lexer.next_token().unwrap(), Token::Identifier("移动".to_string()));
        assert_eq!(lexer.next_token().unwrap(), Token::Identifier("累加器".to_string()));
        assert_eq!(lexer.next_token().unwrap(), Token::Identifier("基址".to_string()));
        assert_eq!(lexer.next_token().unwrap(), Token::Identifier("计数".to_string()));
    }

    #[test]
    fn test_numbers_decimal() {
        let mut lexer = Lexer::new("123 456 0 1000");
        assert_eq!(lexer.next_token().unwrap(), Token::Number(123));
        assert_eq!(lexer.next_token().unwrap(), Token::Number(456));
        assert_eq!(lexer.next_token().unwrap(), Token::Number(0));
        assert_eq!(lexer.next_token().unwrap(), Token::Number(1000));
    }

    #[test]
    fn test_numbers_hexadecimal() {
        let mut lexer = Lexer::new("0x10 0xFF 0x0 0xABCD");
        assert_eq!(lexer.next_token().unwrap(), Token::Number(0x10));
        assert_eq!(lexer.next_token().unwrap(), Token::Number(0xFF));
        assert_eq!(lexer.next_token().unwrap(), Token::Number(0x0));
        assert_eq!(lexer.next_token().unwrap(), Token::Number(0xABCD));
    }

    #[test]
    fn test_numbers_binary() {
        let mut lexer = Lexer::new("0b1010 0b1111 0b0");
        assert_eq!(lexer.next_token().unwrap(), Token::Number(0b1010));
        assert_eq!(lexer.next_token().unwrap(), Token::Number(0b1111));
        assert_eq!(lexer.next_token().unwrap(), Token::Number(0b0));
    }

    #[test]
    fn test_chinese_symbols() {
        let mut lexer = Lexer::new("，【】：");
        assert_eq!(lexer.next_token().unwrap(), Token::Comma);
        assert_eq!(lexer.next_token().unwrap(), Token::LeftBracket);
        assert_eq!(lexer.next_token().unwrap(), Token::RightBracket);
        assert_eq!(lexer.next_token().unwrap(), Token::Colon);
    }

    #[test]
    fn test_english_operators() {
        let mut lexer = Lexer::new("+ - *");
        assert_eq!(lexer.next_token().unwrap(), Token::Plus);
        assert_eq!(lexer.next_token().unwrap(), Token::Minus);
        assert_eq!(lexer.next_token().unwrap(), Token::Asterisk);
    }

    #[test]
    fn test_comments() {
        let mut lexer = Lexer::new("移动 累加器，10 -- 这是注释\n加 累加器，20");
        assert_eq!(lexer.next_token().unwrap(), Token::Identifier("移动".to_string()));
        assert_eq!(lexer.next_token().unwrap(), Token::Identifier("累加器".to_string()));
        assert_eq!(lexer.next_token().unwrap(), Token::Comma);
        assert_eq!(lexer.next_token().unwrap(), Token::Number(10));
        assert_eq!(lexer.next_token().unwrap(), Token::Newline);
        assert_eq!(lexer.next_token().unwrap(), Token::Identifier("加".to_string()));
    }

    #[test]
    fn test_newlines() {
        let mut lexer = Lexer::new("移动\n加\n减");
        assert_eq!(lexer.next_token().unwrap(), Token::Identifier("移动".to_string()));
        assert_eq!(lexer.next_token().unwrap(), Token::Newline);
        assert_eq!(lexer.next_token().unwrap(), Token::Identifier("加".to_string()));
        assert_eq!(lexer.next_token().unwrap(), Token::Newline);
        assert_eq!(lexer.next_token().unwrap(), Token::Identifier("减".to_string()));
    }

    #[test]
    fn test_whitespace() {
        let mut lexer = Lexer::new("  移动   累加器  ");
        assert_eq!(lexer.next_token().unwrap(), Token::Identifier("移动".to_string()));
        assert_eq!(lexer.next_token().unwrap(), Token::Identifier("累加器".to_string()));
    }

    #[test]
    fn test_eof() {
        let mut lexer = Lexer::new("移动");
        assert_eq!(lexer.next_token().unwrap(), Token::Identifier("移动".to_string()));
        assert_eq!(lexer.next_token().unwrap(), Token::Eof);
        assert_eq!(lexer.next_token().unwrap(), Token::Eof); // 多次调用应返回Eof
    }

    #[test]
    fn test_identifier_with_numbers() {
        let mut lexer = Lexer::new("标签1 标签2 变量3");
        assert_eq!(lexer.next_token().unwrap(), Token::Identifier("标签1".to_string()));
        assert_eq!(lexer.next_token().unwrap(), Token::Identifier("标签2".to_string()));
        assert_eq!(lexer.next_token().unwrap(), Token::Identifier("变量3".to_string()));
    }

    #[test]
    fn test_invalid_character() {
        let mut lexer = Lexer::new("移动@累加器");
        assert_eq!(lexer.next_token().unwrap(), Token::Identifier("移动".to_string()));
        let result = lexer.next_token();
        assert!(result.is_err());
        if let Err(AssemblerError::LexerError { message, .. }) = result {
            assert!(message.contains("无法识别"));
        }
    }

    #[test]
    fn test_position_tracking() {
        let mut lexer = Lexer::new("移动\n加\n减");
        lexer.next_token().unwrap(); // 移动
        assert_eq!(lexer.position(), (1, 3));
        lexer.next_token().unwrap(); // Newline
        lexer.next_token().unwrap(); // 加
        assert_eq!(lexer.position(), (2, 2));
    }

    #[test]
    fn test_memory_operand() {
        let mut lexer = Lexer::new("移动 累加器，【基址+源索引+10】");
        assert_eq!(lexer.next_token().unwrap(), Token::Identifier("移动".to_string()));
        assert_eq!(lexer.next_token().unwrap(), Token::Identifier("累加器".to_string()));
        assert_eq!(lexer.next_token().unwrap(), Token::Comma);
        assert_eq!(lexer.next_token().unwrap(), Token::LeftBracket);
        assert_eq!(lexer.next_token().unwrap(), Token::Identifier("基址".to_string()));
        assert_eq!(lexer.next_token().unwrap(), Token::Plus);
        assert_eq!(lexer.next_token().unwrap(), Token::Identifier("源索引".to_string()));
        assert_eq!(lexer.next_token().unwrap(), Token::Plus);
        assert_eq!(lexer.next_token().unwrap(), Token::Number(10));
        assert_eq!(lexer.next_token().unwrap(), Token::RightBracket);
    }
}

